<?php

namespace payment;

use think\facade\Config;
use think\facade\Log;

class AirwallexService
{
    private $clientId;
    private $apiKey;
    private $apiUrl;
    private $accessToken;
    private $tokenExpireTime;
    private $refreshToken;
    private $refreshTokenExpireTime;

    private $cardholder_id;
    private $allowed_currencies;

    private $allowed_merchant_categories;

    private $allowed_transaction_count;

    private $transaction_limits;

    public function __construct()
    {
        $this->clientId = Config::get('airwallex.client_id');
        $this->apiKey = Config::get('airwallex.api_key');
        $this->apiUrl = Config::get('airwallex.api_url');
        $this->cardholder_id = Config::get('airwallex.cardholder_id');
        $this->allowed_currencies = Config::get('airwallex.allowed_currencies');
        $this->allowed_merchant_categories = Config::get('airwallex.allowed_merchant_categories');
        $this->allowed_transaction_count = Config::get('airwallex.allowed_transaction_count');
        $this->transaction_limits = Config::get('airwallex.transaction_limits');

        // 尝试从缓存中获取token
        $this->loadTokenFromCache();
    }

    /**
     * 从缓存加载token
     */
    private function loadTokenFromCache()
    {
        $cache = cache('airwallex_token');
        if ($cache) {
            $this->accessToken = $cache['access_token'];
            $this->tokenExpireTime = $cache['expire_time'];
            $this->refreshToken = $cache['refresh_token'];
            $this->refreshTokenExpireTime = $cache['refresh_expire_time'];
        }
    }

    /**
     * 保存token到缓存
     */
    private function saveTokenToCache()
    {
        $cache = [
            'access_token' => $this->accessToken,
            'expire_time' => $this->tokenExpireTime,
            'refresh_token' => $this->refreshToken,
            'refresh_expire_time' => $this->refreshTokenExpireTime
        ];
        cache('airwallex_token', $cache, 3600 * 24); // 缓存24小时
    }

    /**
     * 获取访问令牌
     * @return string
     */
    private function getAccessToken()
    {
        // 如果token存在且未过期，直接返回
        if ($this->accessToken && time() < $this->tokenExpireTime) {
            return $this->accessToken;
        }

        // 如果refresh token存在且未过期，尝试刷新token
        if ($this->refreshToken && time() < $this->refreshTokenExpireTime) {
            try {
                return $this->refreshAccessToken();
            } catch (\Exception $e) {
                // 刷新失败，继续使用新token
            }
        }

        // 获取新token
        return $this->requestNewAccessToken();
    }

    /**
     * 请求新的访问令牌
     * @return string
     */
    private function requestNewAccessToken()
    {
        $url = $this->apiUrl . '/authentication/login';
        $data = [
            'x-client-id' => $this->clientId,
            'x-api-key' => $this->apiKey
        ];

        $response = $this->request('POST', $url, $data);

        if (isset($response['token'])) {
            $this->accessToken = $response['token'];
            $this->tokenExpireTime = strtotime($response['expires_at']) - 60; // 提前1分钟过期

            // 如果有refresh token，保存
            if (isset($response['refresh_token'])) {
                $this->refreshToken = $response['refresh_token'];
                $this->refreshTokenExpireTime = strtotime($response['refresh_expires_at']) - 60;
            }

            $this->saveTokenToCache();
            return $this->accessToken;
        }

        throw new \Exception('获取访问令牌失败');
    }

    /**
     * 刷新访问令牌
     * @return string
     */
    private function refreshAccessToken()
    {
        $url = $this->apiUrl . '/authentication/refresh';
        $data = [
            'refresh_token' => $this->refreshToken
        ];

        $response = $this->request('POST', $url, $data);

        if (isset($response['token'])) {
            $this->accessToken = $response['token'];
            $this->tokenExpireTime = strtotime($response['expires_at']) - 60;

            // 如果有新的refresh token，更新
            if (isset($response['refresh_token'])) {
                $this->refreshToken = $response['refresh_token'];
                $this->refreshTokenExpireTime = strtotime($response['refresh_expires_at']) - 60;
            }

            $this->saveTokenToCache();
            return $this->accessToken;
        }

        throw new \Exception('刷新访问令牌失败');
    }

    /**
     * 创建支付链接
     * @param array $params 支付参数
     * @return array
     */
    public function createPaymentLink($params)
    {
        $url = $this->apiUrl . '/payment_links';
        $data = [
            'amount' => $params['amount'],
            'currency' => $params['currency'],
            'order_id' => $params['order_id'],
            'description' => $params['description'] ?? '',
            'customer' => [
                'email' => $params['customer_email'],
                'name' => $params['customer_name'] ?? '',
            ],
            'success_url' => $params['success_url'] ?? '',
            'cancel_url' => $params['cancel_url'] ?? '',
        ];

        return $this->request('POST', $url, $data);
    }

    /**
     * 查询支付状态
     * @param string $paymentId 支付ID
     * @return array
     */
    public function getPaymentStatus($paymentId)
    {
        $url = $this->apiUrl . '/payments/' . $paymentId;
        return $this->request('GET', $url);
    }

    /**
     * 创建退款
     * @param array $params 退款参数
     * @return array
     */
    public function createRefund($params)
    {
        $url = $this->apiUrl . '/refunds';
        $data = [
            'payment_id' => $params['payment_id'],
            'amount' => $params['amount'],
            'currency' => $params['currency'],
            'reason' => $params['reason'] ?? '',
        ];

        return $this->request('POST', $url, $data);
    }

    /**
     * 查询退款状态
     * @param string $refundId 退款ID
     * @return array
     */
    public function getRefundStatus($refundId)
    {
        $url = $this->apiUrl . '/refunds/' . $refundId;
        return $this->request('GET', $url);
    }

    public function createVirtualCard($params)
    {
        // 使用示例接口地址，与文档中 POST Create a card 对应
        $url = $this->apiUrl . '/issuing/cards/create';

        $data = [
            "authorization_controls" => [
//                "allowed_currencies" => $this->allowed_currencies,
//                "allowed_merchant_categories" => $this->allowed_merchant_categories,
                "allowed_transaction_count" => $this->allowed_transaction_count,
                "transaction_limits" => $params['transaction_limits'] ?? $this->transaction_limits,
            ],

            "cardholder_id" => $this->cardholder_id,
            "nick_name" => $params['nick_name'] ?? "",
            "created_by" => "card admin",
            "form_factor" => "VIRTUAL",
            "issue_to" => "ORGANISATION",
            "is_personalized" => false,// 可以查看卡号信息
            "program" => [
                "purpose" => "COMMERCIAL",
            ],

            "request_id" => uniqid('card_', true)
        ];

        // 发起 POST 请求，返回请求结果
        return $this->request('POST', $url, $data);
    }

    /**
     * 获取卡片列表
     * @param array $params 查询参数
     * @return array
     */
    public function getCardList($params = [])
    {
        $url = $this->apiUrl . '/issuing/cards';
//        dump($url);
        $query = http_build_query($params);
        if ($query) {
            $url .= '?' . $query;
        }
        return $this->request('GET', $url);
    }

    /**
     * 获取卡片详情
     * @param string $cardId 卡片ID
     * @return array
     */
    public function getCardDetail($cardId)
    {
        $url = $this->apiUrl . '/issuing/cards/' . $cardId . '/details';

        return $this->request('GET', $url);
    }

    public function getCard($cardId)
    {
        $url = $this->apiUrl . '/issuing/cards/' . $cardId;

        return $this->request('GET', $url);
    }

    /**
     * 更新卡片状态
     * @param string $cardId 卡片ID
     * @param string $status 新状态
     * INACTIVE, ACTIVE, CLOSED
     * @return array
     */
    public function updateCardStatus($cardId, $status)
    {
        $url = $this->apiUrl . '/issuing/cards/' . $cardId . '/update';
        $data = [
            'card_status' => $status
        ];
        return $this->request('POST', $url, $data);
    }

    /***
     * 获取卡片限额
     * @param $cardId
     * @return array
     */
    public function getCardLimit($cardId)
    {
        $url = $this->apiUrl . '/issuing/cards/' . $cardId . '/limits';
        return $this->request('GET', $url);
    }

    /**
     * 更新卡片限额
     * @param string $cardId 卡片ID
     * @param array $limits 限额参数
     * @return array
     */
    public function updateCardLimit($params)
    {
        $url = $this->apiUrl . '/issuing/cards/' . $params['card_id'] . '/update';
        $data = [
            'authorization_controls' => [
                'transaction_limits' => $params['transaction_limits']
            ]
        ];
        return $this->request('POST', $url, $data);
    }

    /**
     * 获取卡片交易记录
     * @param string $cardId 卡片ID
     * @param array $params 查询参数
     * @return array
     */
    public function getCardTransactions($params = [])
    {
        $url = $this->apiUrl . '/issuing/transactions';
        $query = http_build_query($params);
        if ($query) {
            $url .= '?' . $query;
        }
        return $this->request('GET', $url);
    }

    /**
     * 获取卡片余额
     * @param string $cardId 卡片ID
     * @return array
     */
    public function getCardBalance($cardId)
    {
        $url = $this->apiUrl . '/issuing/cards/' . $cardId . '/balance';
        return $this->request('GET', $url);
    }

    /**
     * 查询退款状态
     * @param string $refundId 退款ID
     * @return array
     */
    public function virtualAccount()
    {
        $url = $this->apiUrl . '/virtual-account';
        return $this->request('GET', $url);
    }

    /**
     * 发送HTTP请求
     * @param string $method 请求方法
     * @param string $url 请求URL
     * @param array $data 请求数据
     * @return array
     */
    private function request($method, $url, $data = [])
    {
        $ch = curl_init();
        $headers = [
            'Content-Type: application/json',
        ];

        if ($url != $this->apiUrl . '/authentication/login') {
            $headers[] = 'Authorization: Bearer ' . $this->getAccessToken();
        } else {
            $headers[] = 'x-client-id: ' . $this->clientId;
            $headers[] = 'x-api-key: ' . $this->apiKey;
        }

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        if ($method != 'GET' && !empty($data)) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        }
//        trace($data);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);


        curl_close($ch);
//        trace($response);
        if ($httpCode != 200 && $httpCode != 201) {
            trace('Airwallex API Error: ' . $response, 'error');
        }
        return json_decode($response, true);
    }
}